/* eslint-disable */
import Layers from "../layers";
import ArrayUtils from "../commons/array-utils";
import TreeNode from "./tree-node";
import TreeBuilder from "./tree-builder";

/**
 * 默认的数据映射函数
 */
const mapper_default = (ele, ret) => {
    ret.data = ele;

    ret.id = ele.id;
    ret.pid = ele.pid;

    ret.icon = ele.icon;
    ret.label = ele.label;
    ret.checked = ele.checked;
}

/**
 * 组织机构的映射函数
 */
const mapper_dept = (ele, ret) => {
    ret.data = ele;

    ret.id = ele.id;
    ret.pid = ele.pid;

    ret.icon = ele.icon;
    ret.label = ele.name;
    ret.checked = ele.checked;
}

/**
 * 默认的数据映射函数
 */
const mapper_dictionary = (ele, ret) => {
    ret.data = ele;

    ret.id = ele.value;
    ret.pid = '';

    ret.label = ele.label;
}

/**
 * 默认的数据映射函数
 */
const mapper_menu = (ele, ret) => {
    ret.data = ele;

    ret.id = ele.id;
    ret.pid = ele.pid;
    ret.level = ele.level;

    ret.icon = ele.icon;
    ret.label = ele.title;
    ret.checked = ele.checked;
}

/**
 * 构建 TreeBuilder 对象
 *
 * @return {TreeBuilder}
 */
const builder = () => {
    return new TreeBuilder();
}


/**
 * 格式化数据，转换成 TreeNode
 *
 * 如果存在子节点，会递归检索子节点
 *
 * @param e             单独一个元素
 * @param call          格式化参数名设置
 * @return {TreeNode}
 */
const wrapObject = (e, call) => {
    const node = new TreeNode();
    call(e, node);
    if (Layers.isNotEmpty(e.children)) {
        node.children = wrapList(e.children, call);
    }
    return node;
};

/**
 * 格式化数据，转换成 TreeNode
 *
 * 如果存在子节点，会递归检索子节点
 *
 * @param list          单独一个元素
 * @param call          格式化参数名设置
 * @return {[TreeNode]}
 */
const wrapList = (list, call) => {
    return ArrayUtils.wrapArray(list, e => wrapObject(e, call));
}


/**
 * 格式化数据，转换成 TreeNode 数组
 *
 * 如果子节点
 *
 * @param list         集合
 * @param mapper       映射函数
 * @return {[TreeNode]}  至少是一个空的数组
 */
const toTree = (list, mapper = mapper_default) => {
    if (Layers.isEmpty(list)) {
        return [];
    } else {
        return new TreeBuilder().setMapper(mapper).setParents(list).groupBy().getRoot();
    }
}

/**
 * 数据字典与数组合并，形成树形结构
 *
 * @param options - 数据字典
 * @param list - 数据列表
 * @param mapper - 数据映射函数
 * @returns 树形结构
 */
const mergeDictionaryList = (options, list, mapper = mapper_default) => {
    if (options == null) {
        return [];
    } else {
        return new TreeBuilder()
            .setMapper(mapper_dictionary).setParents(options)
            .setMapper(mapper).setChildren(list)
            .groupBy().getParent();
    }
}

/**
 * 取集合中的字段拼接成字符串
 *
 * @param list         集合
 * @param field        字段名
 * @return {[]}        至少是一个空的数组
 */
const getListFields = (list, field) => {
    let res = [];
    if (Layers.isNotEmpty(list)) {
        list.forEach(ele => res.push(ele[field]));
    }
    return res;
}

/**
 * 获取 id 串
 *
 * @param list         集合
 * @return {[]}        至少是一个空的数组
 */
const getIds = (list) => {
    return getListFields(list, 'id');
};

/**
 * 获取 name 串
 *
 * @param list         集合
 * @return {[]}        至少是一个空的数组
 */
const getNames = (list) => {
    return getListFields(list, 'name');
};

/**
 * 获取 label 串
 *
 * @param list         集合
 * @return {[]}        至少是一个空的数组
 */
const getLabels = (list) => {
    return getListFields(list, 'label');
};

/**
 * 遍历所有的节点
 *
 * 注意：遍历无法提前终止
 *
 * @param tree         树
 * @param call         函数回调
 */
const forEach = (tree, call) => {
    if (Layers.isNotEmpty(tree)) {
        let node;
        for (let i = 0; i < tree.length; i++) {
            node = tree[i];
            call(node)
            if (node.hasChildren()) {
                forEach(node.children, call)
            }
        }
    }
};


/**
 * 取出满足条件的第一个元素
 *
 * @param tree       树
 * @param filter     返回 true 的时候，取出该元素
 * @return {TreeNode} 至少是一个空的数组
 */
const findElement = (tree, filter) => {
    if (Layers.isNotEmpty(tree)) {
        let node;
        for (let i = 0; i < tree.length; i++) {
            node = tree[i];
            if (filter(node)) {
                return node;
            }
            if (node.hasChildren()) {
                let ret = findElement(node.children, filter);
                if (ret) {
                    return ret;
                }
            }
        }
    }
};

/**
 * 取出满足条件的所有元素
 *
 * @param tree         树
 * @param filter       返回 true 的时候，取出该元素
 * @return {[TreeNode]} 至少是一个空的数组
 */
const findElements = (tree, filter) => {
    if (Layers.isNotEmpty(tree)) {
        let ret = [];
        forEach(tree, e => {
            if (filter(e)) {
                ret.push(e);
            }
        });
        return ret;
    } else {
        return tree;
    }
};


/**
 * 根据 id 查找特定的节点
 *
 * @param tree         树
 * @param id           ID值
 * @return {TreeNode}  至少是一个空的数组
 */
const getNodeById = (tree, id) => {
    return findElement(tree, e => e.id === id);
};

/**
 * 根据 id 查找特定的节点
 *
 * @param tree         树
 * @param ids          ID值
 * @return {[TreeNode]}
 */
const getNodeByIds = (tree, ids) => {
    return findElements(tree, e => Layers.contain(ids, e.id));
};


/**
 * 取出满足条件的所有元素
 *
 * @param tree         树
 * @param label        模糊检索字符
 * @return {[TreeNode]} 至少是一个空的数组
 */
const searchElements = (tree, label) => {
    if (Layers.isNotEmpty(tree)) {
        // 重置所有状态
        forEach(tree, ele => ele.hit = false);

        // 递归查找
        forEach(tree, e => {
            if (!e.isHit() && e.label.includes(label)) {
                e.setHit(true);
                let node = e;
                while (node.hasParent()) {
                    node = node.parent;
                    if (node.isHit()) {
                        break;
                    } else {
                        node.setHit(true);
                    }
                }
            }
        });

        // 只遍历第一层数据
        return Layers.findElements(tree, ele => ele.isHit());
    } else {
        return tree;
    }
};

/**
 * 取出满足条件的所有元素
 *
 * 扁平化搜索结果，将查到的元素进行同级展示。
 *
 * @param tree         树
 * @param label        模糊检索字符
 * @return {[TreeNode]} 至少是一个空的数组
 */
const smartSearchElements = (tree, label) => {
    if (Layers.isNotEmpty(tree)) {
        const ret = [];

        // 重置所有状态
        forEach(tree, e => {
            e.setHit(e.label.includes(label));
            ret.push(e);
        });

        return ret;
    } else {
        return tree;
    }
};

/**
 * 确定一个数组是否是树
 *
 * 对于 undefined、null 等类型的数据，当作树进行处理。
 *
 * @param list       集合
 * @return {boolean}
 */
const isTree = (list) => {
    if (Layers.isNotEmpty(list)) {
        return list[0] instanceof TreeNode;
    } else {
        return true;
    }
}

/**
 * 内置的数据映射函数
 */
export {mapper_dept, mapper_menu, mapper_default, mapper_dictionary}

/**
 * 树形工具
 */
const Bamboo = {
    mapper_default, mapper_dictionary, mapper_menu, mapper_dept,

    builder, wrapObject, wrapList, toTree,
    mergeDictionaryList,
    getListFields, getIds, getLabels, getNames,
    forEach, findElement, findElements,
    searchElements, smartSearchElements,
    getNodeByIds, getNodeById,
    isTree
};

export default Bamboo;